/** \file    functional.h
  * \brief   all code here has some concern to standard <functional> header of STL in one of three ways
  *			 1) MS compiler's bugs bypass by simplified templates,
  *			 2) Direct enhancements of existing templates,
  *			 3) New independent templates additions in the spirit of <functional>
  * \date    2001, 2002
  * \author  Fedor Chelnokov, Pavel Agapov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/xtd/functional.h,v 1.5 2005/01/23 08:20:57 cscom1r4 Exp $
  */

#ifndef _yatl_functional_h_
#define _yatl_functional_h_

#include <functional>
#include <algorithm>
#include "obj_fun.h"

namespace xtd
{

// TEMPLATE CLASS void_binder1st
template<class Bfn>
	class void_binder1st
	: public std::unary_function<typename Bfn::second_argument_type, void>
{
public:
	typedef typename std::unary_function<typename Bfn::second_argument_type, void>::argument_type argument_type;
public:
	void_binder1st(const Bfn& x,
		const typename Bfn::first_argument_type& y)
		: op(x), value(y) {}
	void operator()(argument_type x) const
		{ (op(value, x)); }
protected:
	Bfn op;
	typename Bfn::first_argument_type value;
};

// TEMPLATE FUNCTION void_bind1st
template<class Bfn, class T> inline
	void_binder1st<Bfn> void_bind1st(const Bfn& x, const T& y)
		{return (void_binder1st<Bfn>(x,
			typename Bfn::first_argument_type(y))); }

/// TEMPLATE CLASS void_binder2nd
template<class Bfn>
	class void_binder2nd
	: public std::unary_function<typename Bfn::first_argument_type, void>
{
public:
	typedef typename std::unary_function<typename Bfn::first_argument_type, void>::argument_type argument_type;
public:
	void_binder2nd(const Bfn& x,
		const typename Bfn::second_argument_type& y)
		: op(x), value(y) {}
	void operator()(argument_type x) const
		{ (op(x, value)); }
protected:
	Bfn op;
	typename Bfn::second_argument_type value;
};

/// TEMPLATE FUNCTION void_bind2nd
template<class Bfn, class T> inline
	void_binder2nd<Bfn> void_bind2nd(const Bfn& x, const T& y)
		{return (void_binder2nd<Bfn>(x,
			typename Bfn::second_argument_type(y))); }

/// TEMPLATE CLASS binder2nd_ref
template<class Bfn>
	class binder2nd_ref
	: public std::unary_function<typename Bfn::first_argument_type, void>
{
public:
	typedef std::unary_function<typename Bfn::first_argument_type, void> base_type;
	typedef typename base_type::argument_type argument_type;
public:
	binder2nd_ref(const Bfn& x, typename Bfn::second_argument_type y)
		: op(x), value(y) {}
	void operator()(argument_type x)
		{ (op(x, value)); }
protected:
	Bfn op;
	typename Bfn::second_argument_type value;
};

/// TEMPLATE FUNCTION void_bind2nd
template<class Bfn, class T> inline
	binder2nd_ref<Bfn> bind2nd_ref(const Bfn& x, const T& y)
		{return (binder2nd_ref<Bfn>(x, typename Bfn::second_argument_type(y))); }

// TEMPLATE CLASS void_mem_fun_t
template<class T>
class void_mem_fun_t : public std::unary_function<T *, void> {
public:
	explicit void_mem_fun_t(void (T::*Pm)())
		: _ptr(Pm) {}
	void operator()(T *p) const
		{ ((p->*_ptr)()); }
private:
	void (T::*_ptr)();
};

// TEMPLATE FUNCTION void_mem_fun
template<class T> inline
	void_mem_fun_t<T> void_mem_fun(void (T::*Pm)())
	{return (void_mem_fun_t<T>(Pm)); }

/// TEMPLATE CLASS void_mem_fun1_t
template<class T, class A>
class void_mem_fun1_t : public std::binary_function<T *, A, void> {
public:
	explicit void_mem_fun1_t(void (T::*Pm)(A))
		: _ptr(Pm) {}
	void operator()(T *p, A arg) const
		{ ((p->*_ptr)(arg)); }
private:
	void (T::*_ptr)(A);
};

/// TEMPLATE FUNCTION void_mem_fun1
template<class T, class A> inline
	void_mem_fun1_t<T, A> void_mem_fun1(void (T::*Pm)(A))
	{ return (void_mem_fun1_t<T, A>(Pm)); }

// in xtd::bind1st and xtd::bind2nd, references and consts are removed

		// TEMPLATE CLASS binder1st
template<class Bfn> class binder1st
	: public std::unary_function<
		typename Bfn::second_argument_type,
		typename Bfn::result_type>
{
public:
	typedef std::unary_function<typename Bfn::second_argument_type, typename Bfn::result_type> base_type;
	typedef typename base_type::argument_type argument_type;
	typedef typename base_type::result_type result_type;
public:
	binder1st(Bfn x, typename Bfn::first_argument_type y)
		: op(x), value(y) { }
	result_type operator()(argument_type x)
		{return (op(value, x)); }
protected:
	Bfn op;
	typename Bfn::first_argument_type value;
};
		// TEMPLATE FUNCTION bind1st
template<class Bfn> inline //attention: do not replace second argument with 'T y'
	binder1st<Bfn> bind1st(Bfn x, typename Bfn::first_argument_type y)
	{ return (binder1st<Bfn>(x, y)); }

		// TEMPLATE CLASS binder2nd
template<class Bfn> class binder2nd
	: public std::unary_function<
		typename Bfn::first_argument_type,
		typename Bfn::result_type>
{
public:
	typedef std::unary_function<typename Bfn::first_argument_type, typename Bfn::result_type> base_type;
	typedef typename base_type::argument_type argument_type;
	typedef typename base_type::result_type result_type;
public:
	binder2nd(Bfn x, typename Bfn::second_argument_type y)
		: op(x), value(y) {}
	result_type operator()(argument_type x)
		{return (op(x, value)); }
protected:
	Bfn op;
	typename Bfn::second_argument_type value;
};

// TEMPLATE FUNCTION bind2nd
template<class Bfn> inline //attention: do not replace second argument with 'T y'
	binder2nd<Bfn> bind2nd(Bfn x, typename Bfn::second_argument_type y)
	{ return (binder2nd<Bfn>(x, y)); }


//please, remove bug in mem_fun1_ref_t definition in VS6:
//"class mem_fun1_ref_t : public binary_function<T *, A, R>" -> "...<T, A, R>"

template <class T, class R>
inline obj_fun_t<T,R> call_mem(T &obj, R (T::*fun)())
	{ return obj_fun(obj, fun); }

// functor that deletes objects in a container of pointers
class deleter {
public:
	template <typename T>
	void operator () (T * ptr) const
		{ delete ptr; }
};

// functor that returns maximum of its operands
template<class T>
struct maximize : public std::binary_function<T, T, T> {
	T operator()(const T& x, const T& y) const
		{ return std::max(x, y); }
};

// functor that returns minimum of its operands
template<class T>
struct minimize : public std::binary_function<T, T, T> {
	T operator()(const T& x, const T& y) const
		{ return std::min(x, y); }
};

template <typename C, typename F>
void for_each(C & c, const F & f)
	{ std::for_each(c.begin(), c.end(), f); }

} //namespace xtd

#endif //yatl_functional_h_
